package com.zebra.gateway;

import com.zebra.common.OfflineType;
import com.zebra.gateway.processor.*;
import com.zebra.gateway.protocol.GatewayCommand;
import com.zebra.gateway.session.Session;
import com.zebra.gateway.session.ZebraAttribute;
import com.zebra.remoting.CommandHandler;
import com.zebra.remoting.config.*;
import com.zebra.remoting.connection.Connection;
import com.zebra.remoting.protocol.CommandType;
import com.zebra.remoting.protocol.PoolType;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;

public class CommandServerHandler implements CommandHandler {
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(CommandServerHandler.class);

    public CommandServerHandler(){
        GwServerProcessorManager.getInstance().registerProcessor(CommandType.BASIS.value(), new ServerBasisHandlerProcessor());
        GwServerProcessorManager.getInstance().registerProcessor(CommandType.LOBBY.value(), new ServerLobbyHandlerProcessor());
        GwServerProcessorManager.getInstance().registerProcessor(CommandType.GAME.value(), new ServerGameHandlerProcessor());
    }

    @Override
    public void handleCommand(ChannelHandlerContext ctx, Object msg) throws Exception {
        GatewayCommand message = (GatewayCommand) msg;
        if (BasisCommandCode.PING.cmd() == message.getCmd()) {
            message.setLogs(true);
            ctx.writeAndFlush(message);  //心跳转发
            return;
        }

        if (BasisCommandCode.REGISTER.cmd() == message.getCmd()) {
            RegisterConnectMessage connectMessage = new RegisterConnectMessage().read(message.getMsgBuf());
            Connection connection = new Connection(ctx.channel(), ServerType.Register, connectMessage.getServerId());
            GwConfigInfoManager.getInstance().registerRA(connection);
            message.setState(StateCode.Success.code());
            message.setMessage(StateMessage.builder().state(StateCode.Success.code()).build());
            message.messageEncoder();
            ctx.writeAndFlush(message);
            GatewayProcessorUtil.sendLinksToRA();
            return;
        }

        CommandType commandType = message.getCommandType();
        GatewayProcessor processor =  GwServerProcessorManager.getInstance().getProcessor(commandType.value());
        PoolType poolType = message.getPoolType();
        Executor executor = poolType.equals(PoolType.DISRUPTOR) ? GwServerProcessorManager.getInstance().getDisruptorByLong(message.getUserId()) : getDefaultExecutor();
        processor.process(ctx, message, executor);

    }

    /**
     *   session is not null
     *  1 表示 断掉的就是本 channel;
     * 0: 表示 ： 断掉的channel 不是session 绑定的channel 即是：
     *            可能断掉的channel 是之前绑定的 前端断线但服务器未收到断线 此时根据心跳断开; 此时一样需要发送到TMS ，因为TMS 不知道断线； 这样会造成 棋牌推送消息
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        Session session = ZebraAttribute.getSession(ctx.channel());
        if (null != session){
            OfflineType type = ctx.channel().equals(session.getChannel()) ? OfflineType.Inactive : OfflineType.InactiveDiff;
            logger.info("Player channel Inactive  {} {} ", type, session.toString());
            GatewayProcessorUtil.sendTmsInactiveChannel(session, type);
            return;
        }

        Connection connection = Connection.getByChannel(ctx.channel());
        if (null != connection){
            GwConfigInfoManager.getInstance().removeRa(connection);
            logger.info("---Server Handler Channel Register Inactive!  Inactive Connection {} ",  GwConfigInfoManager.getInstance().getRaSize(), connection.toString());
            GatewayProcessorUtil.printLog();
            GatewayProcessorUtil.sendLinksToRA();
        }
    }


    private ExecutorService getDefaultExecutor() {
        return GwServerProcessorManager.getInstance().getDefaultExecutor();
    }


}
